package db

import (
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"strconv"
	"strings"
	"sync"
	"time"
	"yan-feeorder/common"
	cfg "ycx-config"
	log "ycx-glog"

	"github.com/syndtr/goleveldb/leveldb/util"

	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/opt"
)

const (
	CBD_MOBILE_AREA  = 'A'
	CBD_CACHE        = 'C'
	CBD_EUSER        = 'E'
	CBD_FEE_PACKAGE  = 'F'
	CBD_FEE_CUSPRICE = 'P'
)

type AreaInfo struct {
	Tid      int    `json:"tid"`
	Mobile   string `json:"mobile"`
	Province string `json:"province"`
	City     string `json:"city"`
}

var sdb *sqlx.DB
var cdb *leveldb.DB
var ro = &opt.ReadOptions{}
var wo = &opt.WriteOptions{}
var euserMutex sync.Mutex
var feePackageMutex sync.Mutex
var feeCusPriceMutex sync.Mutex
var mobileAreaMutex sync.Mutex
var feeOrderMutex sync.Mutex
var feeOrderDoingMutex sync.Mutex

func InitDB(dirverName, dataSource string, cacheLevelDB string) (*sqlx.DB, *leveldb.DB, error) {
	if sdb != nil {
		sdb.Close()
		sdb = nil
	}
	if cdb != nil {
		cdb.Close()
		cdb = nil
	}

	if dirverName == "sqlite3" && dataSource != ":memory:" {
		dataSource = common.EnsureFilePath(dataSource)
	}

	var err error
	sdb, err = sqlx.Open(dirverName, dataSource)
	if err != nil {
		log.Infoln(err)
		return nil, nil, err
	}
	sdb.SetMaxOpenConns(2000)
	sdb.SetMaxIdleConns(100)
	sdb.Ping()

	log.Infoln("open cache_leveldb ", cacheLevelDB)
	cdb, err = leveldb.OpenFile(common.EnsureDir(cacheLevelDB), nil)
	if err != nil {
		log.Infoln(err)
		return nil, nil, err
	}
	//create table

	return sdb, cdb, nil
}

func SDB() *sqlx.DB {
	return sdb
}

func CDB() *leveldb.DB {
	return cdb
}

func Close() {
	if cdb != nil {
		cdb.Close()
		cdb = nil
	}
	if sdb != nil {
		sdb.Close()
		sdb = nil
	}
}

func cacheKey(vType byte, key []byte) []byte {
	return append([]byte{vType}, key...)
}

func MonitorOrder(istart int) ([]map[string]interface{}, error) {
	if sdb == nil {
		return nil, errors.New("sdb is nil")
	}
	sql := cfg.String("monitor.sql")
	var rows *sqlx.Rows
	var err error
	if strings.Contains(sql, "?") {
		rows, err = sdb.Queryx(sql, istart)
	} else {
		rows, err = sdb.Queryx(sql)
	}
	if err != nil {
		log.Errorln(err)
		return nil, err
	}
	rs := common.Rows(rows)
	rows.Close()
	return rs, nil
}

func GetFeePackageInfo(tid int, province string, price int, uid int) map[string]interface{} {
	/*
		$package = TableFeePackage::selectone(array(
		'where' => array(
			array('tid','=',$area['apimarea_type']),		    //运营商
			array('area_buy','=',$area['apimarea_province']),   //号码归属地
			array('price_org','=',$price),						//充值金额
			array('api_uid','=',$_SESSION['__u']['uid']),
		),
		));
	*/
	sql := "SELECT pause,api_type1,api_code1 FROM fee_package WHERE tid=? AND area_buy=? AND price_org=? AND api_uid=?  LIMIT 0, 1"
	//rows, err := sdb.Queryx(sql, tid, province, int(float32(price)/100.0), uid)
	rows, err := sdb.Queryx(sql, tid, province, price, uid)
	if err != nil {
		log.Errorln(err)
		return nil
	}
	rs := common.Rows(rows)
	rows.Close()

	if len(rs) > 0 {
		return rs[0]
	}
	return nil
}

func InsertFeeOrder(orderId string, mobile string, utype string,
	uid int, tid int, province string, city string,
	about string, reqPlus string, pay uint64, price int,
	submitTime string, submitMessage string,
	modulePos string) uint64 {

	payF := float32(float32(pay) / 10000.0)

	sql := "INSERT INTO feeordercache (about,utype,uid,api_uid,tuid,tid,area_buy,area_city,mobile,req_plus,return_order_id,order_id,need_pay,pay,pay_org,pay_rel,submit_time,submit_msg,module_pos) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
	result, err := sdb.Exec(sql,
		about,
		utype,
		uid,
		uid,
		0,
		tid,
		province,
		city,
		mobile,
		reqPlus,
		orderId,
		orderId,
		payF,
		payF,
		price,
		payF,
		submitTime,
		submitMessage,
		modulePos)
	if err != nil {
		log.Errorln(err)
		return 0
	}
	id, err := result.LastInsertId()
	if err != nil {
		log.Errorln(err)
		return 0
	}
	return uint64(id)
}

func GetCount(sql string, args ...interface{}) int {
	strings.Replace(sql, "count(*)", "COUNT(*)", -1)
	rows, err := sdb.Queryx(sql, args...)
	if err != nil {
		return 0
	}
	rs := common.Rows(rows)
	rows.Close()

	if len(rs) == 0 {
		return 0
	}

	return common.ValueToInt(rs[0]["COUNT(*)"], 0)
}

// 10倍性能
func GetMobileArea(mobile string) (tid int, province, city string) {
	if len(mobile) < 7 {
		return
	}

	if cdb != nil {
		// 利用键值数据库提升区域查询性能
		val, err := cdb.Get(cacheKey(CBD_MOBILE_AREA, []byte(mobile[:7])), ro)
		if err != nil {
			log.Infoln(err)
			return
		}
		/*
			var areaInfo AreaInfo
			err = common.JDecode(val, &areaInfo)
			if err != nil {
				log.Infoln(err)
				return
			}
			return areaInfo.Tid, areaInfo.Province, areaInfo.City
		*/
		vals := strings.Split(string(val), ",")
		if len(vals) != 3 {
			return
		}
		tid, _ = strconv.Atoi(vals[0])
		return tid, vals[1], vals[2]
	}
	sql := "SELECT * FROM mobileareax WHERE mobile=? LIMIT 0, 2"
	rows, err := sdb.Queryx(sql, mobile[:7])
	if err != nil {
		return
	}
	rs := common.Rows(rows)
	rows.Close()

	if len(rs) > 0 {
		corp := common.ValueToString(rs[0]["corp"], "")
		province = common.ValueToString(rs[0]["province"], "")
		city = common.ValueToString(rs[0]["city"], "")
		if corp == "移动" {
			tid = 1
		} else if corp == "联通" {
			tid = 2
		} else if corp == "电信" {
			tid = 3
		}
		return
	}

	return
}

func MoveMobileAreaRDSToKV() {
	if cdb == nil || sdb == nil {
		return
	}
	mobileAreaMutex.Lock()
	defer mobileAreaMutex.Unlock()
	iter := cdb.NewIterator(util.BytesPrefix([]byte{CBD_MOBILE_AREA}), nil)
	for iter.Next() {
		dkey := iter.Key()
		cdb.Delete(dkey, wo)
	}
	iter.Release()
	total := GetCount("SELECT COUNT(*) FROM mobileareax")
	if total < 1 {
		return
	}

	pg := 1
	psz := 50000
	begin := psz * (pg - 1)
	for begin < total {
		rows, err := sdb.Queryx("SELECT * FROM mobileareax ORDER BY id ASC LIMIT ?,?",
			begin,
			psz)
		if err != nil {
			return
		}
		rs := common.Rows(rows)
		rows.Close()

		log.Infoln(len(rs))
		for _, v := range rs {
			mobile := common.ValueToString(v["mobile"], "")
			if len(mobile) != 7 {
				continue
			}
			corp := common.ValueToString(v["corp"], "")
			tid := 0
			if corp == "移动" {
				tid = 1
			} else if corp == "联通" {
				tid = 2
			} else if corp == "电信" {
				tid = 3
			}
			str := fmt.Sprintf("%d,%s,%s", tid, common.ValueToString(v["province"], ""), common.ValueToString(v["city"], ""))
			err := cdb.Put(cacheKey(CBD_MOBILE_AREA, []byte(mobile[:7])), []byte(str), wo)
			if err != nil {
				log.Infoln(err)
				return
			}
		}
		//return

		pg++
		begin = psz * (pg - 1)
	}
}

// 10倍性能  查询用户信息
func GetOneEuser(username string) map[string]interface{} {
	if len(username) == 0 {
		return nil
	}
	//	euserMutex.Lock()
	//	defer euserMutex.Unlock()
	if cdb != nil {
		// 利用键值数据库提升区域查询性能
		val, err := cdb.Get(cacheKey(CBD_EUSER, []byte(username)), ro)
		if err != nil {
			log.Infoln(err)
			return nil
		}
		vals := make(map[string]interface{})
		err = json.Unmarshal(val, &vals)
		if err != nil {
			return nil
		}

		return vals
	}
	sql := "SELECT uid,api_pause,api_pause_2,api_key_1,api_key_2,api_ips_1,api_ips_2,password,user_money,limit_money,credit_money FROM euser WHERE username=? LIMIT 0, 1"
	rows, err := sdb.Queryx(sql, username)
	if err != nil {
		return nil
	}
	rs := common.Rows(rows)
	rows.Close()

	if len(rs) == 0 {
		return nil
	}

	return rs[0]
}
func MoveEuserToKv() {
	if cdb == nil || sdb == nil {
		return
	}
	euserMutex.Lock()
	defer euserMutex.Unlock()
	iter := cdb.NewIterator(util.BytesPrefix([]byte{CBD_EUSER}), nil)
	for iter.Next() {
		dkey := iter.Key()
		cdb.Delete(dkey, wo)
	}
	iter.Release()
	total := GetCount("SELECT COUNT(*) FROM euser")
	if total < 1 {
		return
	}

	pg := 1
	psz := 50000
	begin := psz * (pg - 1)
	for begin < total {
		rows, err := sdb.Queryx("SELECT uid,username,api_pause,api_pause_2,api_key_1,api_key_2,api_ips_1,api_ips_2,password,user_money,limit_money,credit_money FROM euser ORDER BY uid ASC LIMIT ?,?",
			begin,
			psz)
		if err != nil {
			return
		}
		rs := common.Rows(rows)
		rows.Close()

		for _, v := range rs {
			str := common.ValueToString(v["username"], "")
			vals := make(map[string]interface{})
			vals["uid"] = common.ValueToInt(v["uid"], 0)
			vals["api_pause"] = common.ValueToInt(v["api_pause"], 0)
			vals["api_pause_2"] = common.ValueToInt(v["api_pause_2"], 0)
			vals["api_key_1"] = common.ValueToString(v["api_key_1"], "")
			vals["api_key_2"] = common.ValueToString(v["api_key_2"], "")
			vals["api_ips_1"] = common.ValueToString(v["api_ips_1"], "")
			vals["api_ips_2"] = common.ValueToString(v["api_ips_2"], "")
			vals["password"] = common.ValueToString(v["password"], "")
			body, err := json.Marshal(vals)
			if err != nil {
				log.Infoln(err)
				return
			}
			err = cdb.Put(cacheKey(CBD_EUSER, []byte(str)), []byte(body), wo)
			if err != nil {
				log.Infoln(err)
				return
			}
		}
		//return

		pg++
		begin = psz * (pg - 1)
	}
}

// 10倍性能  查询用户套餐信息
func GetFeePackage(tid int, province string, city string, price int, uid int) map[string]interface{} {
	if cdb != nil {
		// 利用键值数据库提升区域查询性能
		key := fmt.Sprintf("%d,%s,%s,%s,%d,%d", tid, "city", province, city, price, uid)
		val, err := cdb.Get(cacheKey(CBD_FEE_PACKAGE, []byte(key)), ro)
		if err != nil {
			if err == leveldb.ErrNotFound {
				// 利用键值数据库提升区域查询性能
				key = fmt.Sprintf("%d,%s,%s,%d,%d", tid, "province", province, price, uid)

				val, err = cdb.Get(cacheKey(CBD_FEE_PACKAGE, []byte(key)), ro)
				if err != nil {
					return nil
				}
				vals := make(map[string]interface{})
				err = json.Unmarshal(val, &vals)
				if err != nil {
					return nil
				}

				return vals
			}
			return nil
		}

		vals := make(map[string]interface{})
		err = json.Unmarshal(val, &vals)
		if err != nil {
			return nil
		}

		return vals
	}
	sql := "SELECT pause,api_type1,api_code1 FROM fee_package WHERE tid=? AND area_buy=? AND price_org=? AND api_uid=? AND pkg_type=? AND area_city=?  LIMIT 0, 1"
	rows, err := sdb.Queryx(sql, tid, province, price, uid, "city", city)
	if err != nil {
		log.Errorln(err)
		return nil
	}
	rs := common.Rows(rows)
	rows.Close()

	if len(rs) > 0 {
		return rs[0]
	} else {
		sql = "SELECT pause,api_type1,api_code1 FROM fee_package WHERE tid=? AND area_buy=? AND price_org=? AND api_uid=? AND pkg_type=?  LIMIT 0, 1"
		rows, err = sdb.Queryx(sql, tid, province, price, uid, "province")
		if err != nil {
			log.Errorln(err)
			return nil
		}
		rs = common.Rows(rows)
		rows.Close()

		if len(rs) > 0 {
			return rs[0]
		}
	}
	return nil
}
func MoveFeePackageToKv() {
	if cdb == nil || sdb == nil {
		return
	}
	feePackageMutex.Lock()
	defer feePackageMutex.Unlock()
	iter := cdb.NewIterator(util.BytesPrefix([]byte{CBD_FEE_PACKAGE}), nil)
	for iter.Next() {
		dkey := iter.Key()
		cdb.Delete(dkey, wo)
	}
	iter.Release()
	total := GetCount("SELECT COUNT(*) FROM fee_package")
	if total < 1 {
		return
	}

	pg := 1
	psz := 50000
	begin := psz * (pg - 1)
	for begin < total {
		rows, err := sdb.Queryx("SELECT tid,pkg_type,area_buy,area_city,price_org,api_uid,pause,api_type1,api_code1 FROM fee_package ORDER BY id ASC LIMIT ?,?",
			begin,
			psz)
		if err != nil {
			return
		}
		rs := common.Rows(rows)
		rows.Close()

		log.Infoln(len(rs))
		for _, v := range rs {
			key := fmt.Sprintf("%d,%s,%s,%d,%d", common.ValueToInt(v["tid"], 0), common.ValueToString(v["pkg_type"], ""), common.ValueToString(v["area_buy"], ""), common.ValueToInt(v["price_org"], 0), common.ValueToInt(v["api_uid"], 0))
			if common.ValueToString(v["pkg_type"], "") == "city" {
				key = fmt.Sprintf("%d,%s,%s,%s,%d,%d", common.ValueToInt(v["tid"], 0), common.ValueToString(v["pkg_type"], ""), common.ValueToString(v["area_buy"], ""), common.ValueToString(v["area_city"], ""), common.ValueToInt(v["price_org"], 0), common.ValueToInt(v["api_uid"], 0))
			}

			vals := make(map[string]interface{})
			vals["pause"] = common.ValueToInt(v["pause"], 0)
			vals["api_type1"] = common.ValueToString(v["api_type1"], "")
			vals["api_code1"] = common.ValueToString(v["api_code1"], "")
			body, err := json.Marshal(vals)
			if err != nil {
				log.Infoln(err)
				return
			}
			err = cdb.Put(cacheKey(CBD_FEE_PACKAGE, []byte(key)), []byte(body), wo)
			if err != nil {
				log.Infoln(err)
				return
			}
		}
		//return

		pg++
		begin = psz * (pg - 1)
	}
}

// 10倍性能  查询用户产品折扣信息
func GetFeeCusPrice(uid int, tid int, province string, city string, price int) uint64 {
	if cdb != nil {
		// 利用键值数据库提升区域查询性能
		key := fmt.Sprintf("%d,%d,%s,%s,%s,%d", uid, tid, "city", province, city, price)

		val, err := cdb.Get(cacheKey(CBD_FEE_CUSPRICE, []byte(key)), ro)
		if err != nil {
			if err == leveldb.ErrNotFound {
				// 利用键值数据库提升区域查询性能
				key = fmt.Sprintf("%d,%d,%s,%s,%d", uid, tid, "province", province, price)

				val, err = cdb.Get(cacheKey(CBD_FEE_CUSPRICE, []byte(key)), ro)
				if err != nil {
					if err == leveldb.ErrNotFound {

					} else {
						//log.Infoln(err, key)
					}
				}
			} else {
				//log.Infoln(err, key)
			}
			log.Infoln(err, key)
		}
		priceRate := 1.0
		if !common.ValueIsEmpty(val) {
			priceRate = common.ValueToFloat(val, 1.0)
		}
		pRate := int(priceRate * 10000)
		return uint64(pRate * price)
	}

	sql := "SELECT price_rate FROM feepricemanage WHERE uid=? AND tid=? AND area_buy=? AND price_org=? AND pkg_type=? AND area_city=?"
	rows, err := sdb.Queryx(sql, uid, tid, province, price, "city", city)
	if err != nil {
		log.Errorln(err)
		return uint64(common.ValueToFloat(price, 1.0) * 10000.0)
	}
	rs := common.Rows(rows)
	rows.Close()

	priceRate := 1.0
	if len(rs) >= 1 {
		priceRate = common.ValueToFloat(rs[0]["price_rate"], 1.0)
	} else {
		sql = "SELECT price_rate FROM feepricemanage WHERE uid=? AND tid=? AND area_buy=? AND price_org=? AND pkg_type=?"
		rows, err = sdb.Queryx(sql, uid, tid, province, price, "province")
		if err != nil {
			log.Errorln(err)
			return uint64(common.ValueToFloat(price, 1.0) * 10000.0)
		}
		rs = common.Rows(rows)
		rows.Close()

		if len(rs) >= 1 {
			priceRate = common.ValueToFloat(rs[0]["price_rate"], 1.0)
		}
	}
	return uint64(priceRate * common.ValueToFloat(price, 1.0) * 10000.0)
}
func MoveFeeCusPriceToKv() {
	if cdb == nil || sdb == nil {
		return
	}
	feeCusPriceMutex.Lock()
	defer feeCusPriceMutex.Unlock()
	iter := cdb.NewIterator(util.BytesPrefix([]byte{CBD_FEE_CUSPRICE}), nil)
	for iter.Next() {
		dkey := iter.Key()
		cdb.Delete(dkey, wo)
	}
	iter.Release()

	total := GetCount("SELECT COUNT(*) FROM feepricemanage")
	if total < 1 {
		return
	}

	pg := 1
	psz := 50000
	begin := psz * (pg - 1)
	for begin < total {
		rows, err := sdb.Queryx("SELECT uid,pkg_type,tid,price_org,area_buy,area_city,price_rate FROM feepricemanage ORDER BY aid ASC LIMIT ?,?",
			begin,
			psz)
		if err != nil {
			return
		}
		rs := common.Rows(rows)
		rows.Close()

		log.Infoln(len(rs))
		for _, v := range rs {
			key := fmt.Sprintf("%d,%d,%s,%s,%d", common.ValueToInt(v["uid"], 0), common.ValueToInt(v["tid"], 0), common.ValueToString(v["pkg_type"], ""), common.ValueToString(v["area_buy"], ""), common.ValueToInt(v["price_org"], 0))
			if common.ValueToString(v["pkg_type"], "") == "city" {
				key = fmt.Sprintf("%d,%d,%s,%s,%s,%d", common.ValueToInt(v["uid"], 0), common.ValueToInt(v["tid"], 0), common.ValueToString(v["pkg_type"], ""), common.ValueToString(v["area_buy"], ""), common.ValueToString(v["area_city"], ""), common.ValueToInt(v["price_org"], 0))
			}
			str := fmt.Sprintf("%0.4f", common.ValueToFloat(v["price_rate"], 1.0))
			err := cdb.Put(cacheKey(CBD_FEE_CUSPRICE, []byte(key)), []byte(str), wo)
			if err != nil {
				log.Infoln(err)
				return
			}
		}
		//return

		pg++
		begin = psz * (pg - 1)
	}
}
func OneEUser(username string) map[string]interface{} {
	if len(username) == 0 {
		return nil
	}
	sql := "SELECT uid,api_pause,api_pause_2,api_key_1,api_key_2,api_ips_1,api_ips_2,password,user_money,limit_money,credit_money FROM euser WHERE username=? LIMIT 0, 1"
	rows, err := sdb.Queryx(sql, username)
	if err != nil {
		log.Errorln(err)
		return nil
	}
	rs := common.Rows(rows)
	rows.Close()

	if len(rs) == 0 {
		return nil
	}

	return rs[0]
}

func PayOrderFld(sess map[string]interface{}, utype string, muid int, uid int, cpnum float64, orderId string, about string) error {

	if utype == "user" {

		sql := "SELECT user_money FROM user WHERE uid=? LIMIT 0, 1"
		rows, err := sdb.Queryx(sql, muid)
		if err != nil {
			log.Errorln(err)
			return err
		}
		rs := common.Rows(rows)
		rows.Close()
		if len(rs) == 0 {
			return errors.New("1#len(rs) == 0")
		}
		mone := rs[0]

		if cpnum == 0 {
			about = "您已成功获得此次充值!"
		}
		if cpnum < 0 {
			needMoney := common.ValueToFloat(mone["user_money"], 0.0) - math.Abs(cpnum/10000)
			wtime := common.TimeFormat(time.Now(), "yyyy-MM-dd HH:mm:ss")
			sqli := "INSERT INTO paycouponlog (uid,order_sn,muid,user_money,cpcr,type_desc,cpabout,status,now_count,wtime) VALUES (?,?,?,?,?,?,?,?,?,?)"
			_, err := sdb.Exec(sqli,
				uid,
				orderId,
				muid,
				cpnum/10000,
				"",
				"话费充值",
				about,
				1,
				needMoney,
				wtime)
			if err != nil {
				log.Errorln(err)
				return err
			}

			DecUserMoney(muid, math.Abs(cpnum), about, sess)
		} else {
			needMoney := common.ValueToFloat(mone["user_money"], 0.0) + math.Abs(cpnum/10000)
			wtime := common.TimeFormat(time.Now(), "yyyy-MM-dd HH:mm:ss")
			sqli := "INSERT INTO paycouponlog (uid,order_sn,muid,user_money,cpcr,type_desc,cpabout,status,now_count,wtime) VALUES (?,?,?,?,?,?,?,?,?,?)"
			_, err := sdb.Exec(sqli,
				uid,
				orderId,
				muid,
				cpnum/10000,
				"",
				"话费充值",
				about,
				1,
				needMoney,
				wtime)
			if err != nil {
				log.Errorln(err)
				return err
			}

			AddUserMoney(muid, cpnum, about, sess)
		}

	} else if utype == "euser" {
		sql := "SELECT user_money FROM euser WHERE uid=? LIMIT 0, 1"
		rows, err := sdb.Queryx(sql, muid)
		if err != nil {
			log.Errorln(err)
			return err
		}
		rs := common.Rows(rows)
		rows.Close()

		if len(rs) == 0 {
			return errors.New("2#len(rs) == 0")
		}
		mone := rs[0]

		if cpnum == 0 {
			about = "您已成功获得此次充值!"
		}
		if cpnum < 0 {
			needMoney := common.ValueToFloat(mone["user_money"], 0.0) - math.Abs(cpnum/10000)
			wtime := common.TimeFormat(time.Now(), "yyyy-MM-dd HH:mm:ss")
			sqli := "INSERT INTO epaycouponlog (uid,order_sn,muid,user_money,cpcr,type_desc,cpabout,status,now_count,wtime) VALUES (?,?,?,?,?,?,?,?,?,?)"
			_, err := sdb.Exec(sqli,
				uid,
				orderId,
				muid,
				cpnum/10000,
				"",
				"话费充值",
				about,
				1,
				needMoney,
				wtime,
			)
			if err != nil {
				log.Errorln(err)
				return err
			}
			DecEuserMoney(muid, math.Abs(cpnum), about, sess)
		} else {
			needMoney := common.ValueToFloat(mone["user_money"], 0.0) + math.Abs(cpnum/10000)
			wtime := common.TimeFormat(time.Now(), "yyyy-MM-dd HH:mm:ss")
			sqli := "INSERT INTO epaycouponlog (uid,order_sn,muid,user_money,cpcr,type_desc,cpabout,status,now_count,wtime) VALUES (?,?,?,?,?,?,?,?,?,?)"
			_, err := sdb.Exec(sqli,
				uid,
				orderId,
				muid,
				cpnum/10000,
				"",
				"话费充值",
				about,
				1,
				needMoney,
				wtime,
			)
			if err != nil {
				log.Errorln(err)
				return err
			}
			AddEuserMoney(muid, cpnum, about, sess)
		}
	}

	return nil
}

func AddUserMoney(uid int, num float64, title string, sess map[string]interface{}) bool {
	re := false
	if !common.ValueIsEmpty(uid) && num >= 0 {
		re = AddPayLog(
			uid,
			num,
			title,
			sess,
		)
	}
	return re
}

func DecUserMoney(uid int, num float64, title string, sess map[string]interface{}) bool {
	re := false
	if !common.ValueIsEmpty(uid) && num >= 0 {
		re = AddPayLog(
			uid,
			(-1)*num,
			title,
			sess,
		)
	}
	return re
}

func AddEuserMoney(uid int, num float64, title string, sess map[string]interface{}) bool {

	re := false
	if !common.ValueIsEmpty(uid) && num >= 0 {
		re = AddEPayLog(
			uid,
			num,
			title,
			sess,
		)
	}
	return re
}

func DecEuserMoney(uid int, num float64, title string, sess map[string]interface{}) bool {

	re := false
	if !common.ValueIsEmpty(uid) && num >= 0 {
		re = AddEPayLog(
			uid,
			(-1)*num,
			title,
			sess,
		)
	}
	return re
}

func AddPayLog(userId int, userMoney float64, changeDesc string, sess map[string]interface{}) bool {

	if userMoney < 0 {
		gcount := GetCount("SELECT COUNT(*) FROM user Where uid = ? and user_money >= ?", userId, math.Abs(userMoney/10000))
		if gcount == 0 {
			return false
		}
	}

	/* 插入帐户变动记录 */
	changeTime := common.TimeFormat(time.Now(), "yyyy-MM-dd HH:mm:ss")
	sql := "INSERT INTO payaccountlog (user_id,user_money,change_desc,change_time,change_type) VALUES (?,?,?,?,?)"
	_, err := sdb.Exec(sql,
		userId,
		userMoney/10000,
		changeDesc,
		changeTime,
		99,
	)
	if err != nil {
		log.Errorln(err)
		return false
	}
	/* 更新用户信息 */

	sqli := "UPDATE user SET user_money=user_money-? WHERE uid=?"
	_, err = sdb.Exec(sqli,
		userMoney/10000,
		userId,
	)
	if err != nil {
		log.Errorln(err)
		return false
	}
	if sess != nil {
		sqls := "SELECT user_money FROM user WHERE uid=? LIMIT 0, 1"
		rows, err := sdb.Queryx(sqls, userId)
		if err != nil {
			log.Errorln(err)
			return false
		}
		rs := common.Rows(rows)
		rows.Close()

		if len(rs) == 0 {
			log.Errorln("#重大错误")
			return false
		}
		mone := rs[0]
		sess["user_money"] = mone["user_money"]
	}
	return true
}

func AddEPayLog(userId int, userMoney float64, changeDesc string, sess map[string]interface{}) bool {

	if userMoney < 0 && userId != 1 {
		gcount := GetCount("SELECT COUNT(*) FROM euser Where uid = ? and user_money >= ?", userId, math.Abs(userMoney/10000))
		if gcount == 0 {
			return false
		}
	}

	/* 插入帐户变动记录 */
	changeTime := common.TimeFormat(time.Now(), "yyyy-MM-dd HH:mm:ss")
	sql := "INSERT INTO epayaccountlog (user_id,user_money,change_desc,change_time,change_type) VALUES (?,?,?,?,?)"
	_, err := sdb.Exec(sql,
		userId,
		userMoney/10000,
		changeDesc,
		changeTime,
		99,
	)
	if err != nil {
		log.Errorln(err)
		return false
	}
	/* 更新用户信息 */

	sqli := "UPDATE euser SET user_money=user_money+?,sys_money=sys_money+? WHERE uid=?"
	_, err = sdb.Exec(sqli,
		userMoney/10000,
		userMoney/10000,
		userId,
	)
	if err != nil {
		log.Errorln(err)
		return false
	}
	if sess != nil {
		sqls := "SELECT user_money FROM euser WHERE uid=? LIMIT 0, 1"
		rows, err := sdb.Queryx(sqls, userId)
		if err != nil {
			log.Errorln(err)
			return false
		}
		rs := common.Rows(rows)
		rows.Close()

		if len(rs) == 0 {
			log.Errorln("#重大错误")
			return false
		}
		mone := rs[0]
		sess["user_money"] = mone["user_money"]
		sess["sys_money"] = mone["sys_money"]
	}
	return true
}

//订单重试
func FeeLimitFailRetry(uid int) int {

	sqls := "SELECT fail_retries FROM order_limit WHERE uid=? LIMIT 0, 1"
	rows, err := sdb.Queryx(sqls, uid)
	if err != nil {
		log.Errorln(err)
		return 0
	}
	rs := common.Rows(rows)
	rows.Close()

	if len(rs) == 0 {
		return 0
	}
	mone := rs[0]
	return common.ValueToInt(mone["fail_retries"], 0)
}

//数据更新请求连接
func SqlBuildQuery(kvs map[string]interface{}) string {
	var prestr string
	var keys []string
	for k := range kvs {
		keys = append(keys, k)
	}
	ln := len(keys)
	for i := 0; i < ln; i++ {
		key := keys[i]
		value := common.ValueToString(kvs[key], "")

		if i == ln-1 { //拼接时，不包括最后一个,字符
			prestr = prestr + key + "=" + "'" + value + "'"
		} else {
			prestr = prestr + key + "=" + "'" + value + "'" + ","
		}
	}

	return prestr
}

//更新订单
func ResultStatusUpdate(orderId string, res map[string]interface{}) bool {
	info := make(map[string]interface{})
	if !common.ValueIsEmpty(res["need_pay"]) {
		info["need_pay"] = res["need_pay"]
	}
	if !common.ValueIsEmpty(res["pay"]) {
		info["pay"] = res["pay"]
	}
	if !common.ValueIsEmpty(res["pay_rel"]) {
		info["pay_rel"] = res["pay_rel"]
	}
	if !common.ValueIsEmpty(res["price_self"]) {
		info["price_self"] = res["price_self"]
	}
	if common.ValueIsEmpty(res["submit_status"]) && !common.ValueIsEmpty(res["result_status"]) {
		res["submit_status"] = "success"
	}
	submit_status := common.ValueToString(res["submit_status"], "")
	if submit_status == "success" || submit_status == "fail" {
		if res["submit_status"] == "fail" {
			res["result_status"] = "fail"
		}
		if !common.ValueIsEmpty(res["result_status"]) {
			info["result_time"] = common.TimeFormat(time.Now(), "yyyy-MM-dd HH:mm:ss")
			if common.ValueToString(res["result_status"], "") == "success" {
				if common.ValueIsEmpty(res["result_msg"]) {
					res["result_msg"] = "成功"
				}
				info["result_msg"] = res["result_msg"]
				info["result_status"] = "success"
				query := SqlBuildQuery(info)
				sql := "UPDATE feeordercache SET " + query + " WHERE order_id=?"
				_, err := sdb.Exec(sql,
					orderId,
				)
				if err != nil {
					return false
				}
			} else {
				if common.ValueIsEmpty(res["result_msg"]) {
					res["result_msg"] = "失败"
				}
				info["result_msg"] = res["result_msg"]
				info["result_status"] = "fail"
				query := SqlBuildQuery(info)
				sql := "UPDATE feeordercache SET " + query + " WHERE order_id=?"
				_, err := sdb.Exec(sql,
					orderId,
				)
				if err != nil {
					return false
				}
			}
		} else {
			info["result_msg"] = "处理中"
			info["result_status"] = "doing"
			query := SqlBuildQuery(info)
			sql := "UPDATE feeordercache SET " + query + " WHERE order_id=?"
			_, err := sdb.Exec(sql,
				orderId,
			)
			if err != nil {
				return false
			}
		}
		return true
	}
	return true
}

func InsertFeeOrderDoing(ouinfo map[string]interface{}) bool {
	sql := "INSERT INTO fee_order_doing (result_status,result_msg,submit_time,response_msg2,did_order_id,did_is,module_pos) VALUES (?,?,?,?,?,?,?)"
	_, err := sdb.Exec(sql,
		ouinfo["result_status"],
		ouinfo["result_msg"],
		ouinfo["result_time"],
		ouinfo["response_msg2"],
		ouinfo["did_order_id"],
		ouinfo["did_is"],
		ouinfo["module_pos"])
	if err != nil {
		return false
	}
	return true
}
func UpdateFeeOrderCache(result_status string, retries int, result_time string, ocid int) bool {
	sql := "UPDATE feeordercache SET result_status = ?,retries = ?,result_time = ? WHERE ocid = ?"
	_, err := sdb.Exec(
		sql,
		result_status,
		retries,
		result_time,
		ocid)
	if err != nil {
		log.Infoln(err)
		return false
	}
	return true
}

func SelectTableFeeOrderCache(orderid string) map[string]interface{} {

	sql := "SELECT retries,ocid FROM feeordercache WHERE order_id = ? LIMIT 0, 1"
	res, err := sdb.Queryx(sql, orderid)
	if common.ValueIsEmpty(res) {
		log.Errorln(err)
	}
	rs := common.Rows(res)
	res.Close()
	if len(rs[0]) == 0 {
		log.Errorln(err)
	}
	return rs[0]
}

func CopyOrder() bool {
	if sdb == nil {
		return false
	}

	feeOrderMutex.Lock()
	defer feeOrderMutex.Unlock()

	nTime := time.Now()
	yesTime := nTime.AddDate(0, 0, -1)
	logDay := yesTime.Format("2006-01-02 00:00:00")
	log.Infoln(logDay)
	total := GetCount("SELECT COUNT(*) FROM feeordercache WHERE submit_time <? AND __check_next_time = '2099-01-01 00:00:00' AND result_status IN ('success','fail')", logDay)
	if total < 1 {
		return false
	}
	log.Infoln(total)
	pg := 1
	psz := 50000
	begin := psz * (pg - 1)
	for begin < total {
		rows, err := sdb.Queryx("SELECT * FROM feeordercache WHERE submit_time <? AND __check_next_time = '2099-01-01 00:00:00' AND result_status IN ('success','fail') ORDER BY ocid ASC LIMIT ?,?",
			logDay,
			begin,
			psz)
		if err != nil {
			return false
		}
		rs := common.Rows(rows)
		rows.Close()

		log.Infoln(len(rs))
		for _, v := range rs {
			rowa, err := sdb.Queryx("SELECT ocid FROM feeordercache_bak WHERE ocid=?",
				v["ocid"])
			rowa.Close()
			if err != nil {
				log.Errorln(err)
				log.Infoln("#5")
				continue
			}
			rss := common.Rows(rowa)

			if len(rss) > 0 {
				continue
			}

			sql := "INSERT INTO feeordercache_bak (ocid,api_uid,utype,uid,tuid,tid,area_buy,area_city,mobile,order_id,about,need_pay,pay,pay_org,pay_rel,price_self,submit_msg,submit_time,result_status,result_msg,result_time,req_plus,refund_flag,module_pos,__check_count,__check_next_time) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
			result, err := sdb.Exec(sql,
				v["ocid"],
				v["api_uid"],
				v["utype"],
				v["uid"],
				v["tuid"],
				v["tid"],
				v["area_buy"],
				v["area_city"],
				v["mobile"],
				v["order_id"],
				v["about"],
				v["need_pay"],
				v["pay"],
				v["pay_org"],
				v["pay_rel"],
				v["price_self"],
				v["submit_msg"],
				v["submit_time"],
				v["result_status"],
				v["result_msg"],
				v["result_time"],
				v["req_plus"],
				v["refund_flag"],
				v["module_pos"],
				v["__check_count"],
				v["__check_next_time"])
			if err != nil {
				log.Errorln(err)
				continue
			}
			id, err := result.LastInsertId()
			if err != nil {
				log.Errorln(err)
				continue
			}
			if !common.ValueIsEmpty(id) {
				delSql := "DELETE FROM feeordercache WHERE ocid = ?"
				_, err := sdb.Exec(delSql, v["ocid"])
				if err != nil {
					log.Errorln(err)
					continue
				}
			}
		}
		//return

		pg++
		begin = psz * (pg - 1)
	}
	return true
}

func CopyOrderDing() bool {
	if sdb == nil {
		return false
	}

	feeOrderDoingMutex.Lock()
	defer feeOrderDoingMutex.Unlock()

	nTime := time.Now()
	yesTime := nTime.AddDate(0, 0, -1)
	logDay := yesTime.Format("2006-01-02 00:00:00")

	total := GetCount("SELECT COUNT(*) FROM fee_order_doing WHERE submit_time <? AND result_status IN ('success','fail')", logDay)
	if total < 1 {
		return false
	}

	pg := 1
	psz := 50000
	begin := psz * (pg - 1)
	for begin < total {
		rows, err := sdb.Queryx("SELECT * FROM fee_order_doing WHERE submit_time <? AND result_status IN ('success','fail') ORDER BY odid ASC LIMIT ?,?",
			logDay,
			begin,
			psz)
		if err != nil {
			return false
		}
		rs := common.Rows(rows)
		rows.Close()

		log.Infoln(len(rs))
		for _, v := range rs {
			rowa, err := sdb.Queryx("SELECT odid FROM fee_order_doing_bak WHERE odid=?",
				v["odid"])

			rss := common.Rows(rowa)
			rowa.Close()
			if err != nil {
				log.Errorln(err)
				log.Infoln("#5")
				continue
			}
			if len(rss) > 0 {
				continue
			}
			sql := "INSERT INTO fee_order_doing_bak (odid,utype,uid,tuid,tid,area_buy,area_city,mobile,order_id,api_type,api_code,param1,param2,pay,pay_org,price_self,submit_msg,submit_time,submit_status,result_status,result_msg,result_time,response_msg1,response_msg2,did_order_id,did_is,module_pos,__getres_count,__getres_next_time) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
			result, err := sdb.Exec(sql,
				v["odid"],
				v["utype"],
				v["uid"],
				v["tuid"],
				v["tid"],
				v["area_buy"],
				v["area_city"],
				v["mobile"],
				v["order_id"],
				v["api_type"],
				v["api_code"],
				v["param1"],
				v["param2"],
				v["pay"],
				v["pay_org"],
				v["price_self"],
				v["submit_msg"],
				v["submit_time"],
				v["submit_status"],
				v["result_status"],
				v["result_msg"],
				v["result_time"],
				v["response_msg1"],
				v["response_msg2"],
				v["did_order_id"],
				v["did_is"],
				v["module_pos"],
				v["__getres_count"],
				v["__getres_next_time"])
			if err != nil {
				log.Errorln(err)
				continue
			}
			id, err := result.LastInsertId()
			if err != nil {
				log.Errorln(err)
				continue
			}
			if !common.ValueIsEmpty(id) {
				delSql := "DELETE FROM fee_order_doing WHERE odid = ?"
				_, err := sdb.Exec(delSql, v["odid"])
				if err != nil {
					log.Errorln(err)
					continue
				}
			}
		}
		//return

		pg++
		begin = psz * (pg - 1)
	}
	return true
}
